package com.datacenter.service;

import com.datacenter.entity.*;
import com.datacenter.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 实时监控服务
 * 
 * 业务含义：
 * 实现场景1的数据资产实时监控功能，包括：
 * - 资源实时状态监控（储量、新增量、启用/禁用占比）
 * - 接口调用监控（实时调用量、峰值、失败率）
 * - 异常行为预警（频繁下载、调用失败、峰值异常）
 */
@Slf4j
@Service
public class RealtimeMonitorService {
    
    @Autowired
    private ResourceMetadataMapper resourceMetadataMapper;
    
    @Autowired
    private ApiCallLogMapper apiCallLogMapper;
    
    @Autowired
    private DownloadLogMapper downloadLogMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String REDIS_KEY_PREFIX = "monitor:";
    private static final String API_CALL_COUNT_KEY = "api_call_count";
    private static final String DOWNLOAD_COUNT_KEY = "download_count";
    private static final String FAILED_CALL_COUNT_KEY = "failed_call_count";
    private static final String IP_DOWNLOAD_COUNT_KEY = "ip_download_count";
    
    /**
     * 监听接口调用日志，进行实时监控
     * 业务含义：实时处理接口调用数据，更新监控指标
     */
    @KafkaListener(topics = "api-call-log", groupId = "monitor-group")
    public void handleApiCallLog(ApiCallLog callLog) {
        log.debug("处理接口调用日志：{}", callLog.getApiUrl());
        
        // 更新实时调用量
        updateRealtimeCallCount(callLog);
        
        // 检查调用失败率
        checkCallFailureRate(callLog);
        
        // 检查峰值异常
        checkPeakAnomaly(callLog);
    }
    
    /**
     * 监听下载日志，进行实时监控
     * 业务含义：实时处理下载数据，检测异常下载行为
     */
    @KafkaListener(topics = "download-log", groupId = "monitor-group")
    public void handleDownloadLog(DownloadLog downloadLog) {
        log.debug("处理下载日志：{}", downloadLog.getFileName());
        
        // 检查异常下载行为
        checkAbnormalDownload(downloadLog);
    }
    
    /**
     * 更新实时调用量统计
     * 业务含义：统计每分钟的接口调用量，用于峰值监控
     */
    private void updateRealtimeCallCount(ApiCallLog callLog) {
        String minuteKey = REDIS_KEY_PREFIX + API_CALL_COUNT_KEY + ":" + 
                          callLog.getCallTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        
        redisTemplate.opsForValue().increment(minuteKey);
        redisTemplate.expire(minuteKey, 1, TimeUnit.HOURS);
        
        // 按部门统计
        String deptKey = REDIS_KEY_PREFIX + "dept_call_count:" + callLog.getDepartment() + ":" +
                        callLog.getCallTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        redisTemplate.opsForValue().increment(deptKey);
        redisTemplate.expire(deptKey, 1, TimeUnit.HOURS);
    }
    
    /**
     * 检查调用失败率
     * 业务含义：监控接口调用失败率，超过5%时触发预警
     */
    private void checkCallFailureRate(ApiCallLog callLog) {
        if (callLog.getStatusCode() != 200) {
            String failedKey = REDIS_KEY_PREFIX + FAILED_CALL_COUNT_KEY + ":" + 
                              callLog.getCallTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
            redisTemplate.opsForValue().increment(failedKey);
            redisTemplate.expire(failedKey, 1, TimeUnit.HOURS);
            
            // 检查失败率是否超过阈值
            checkFailureRateThreshold(callLog.getCallTime());
        }
    }
    
    /**
     * 检查峰值异常
     * 业务含义：检测单接口分钟调用量是否超过历史峰值2倍
     */
    private void checkPeakAnomaly(ApiCallLog callLog) {
        String currentMinute = callLog.getCallTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        String currentCountKey = REDIS_KEY_PREFIX + API_CALL_COUNT_KEY + ":" + currentMinute;
        
        Long currentCount = (Long) redisTemplate.opsForValue().get(currentCountKey);
        if (currentCount != null) {
            // 获取历史峰值（这里简化处理，实际应该从历史数据中获取）
            Long historicalPeak = getHistoricalPeak(callLog.getApiUrl());
            if (historicalPeak != null && currentCount > historicalPeak * 2) {
                log.warn("检测到峰值异常：接口{}当前调用量{}超过历史峰值{}的2倍", 
                        callLog.getApiUrl(), currentCount, historicalPeak);
                // 发送告警
                sendPeakAnomalyAlert(callLog.getApiUrl(), currentCount, historicalPeak);
            }
        }
    }
    
    /**
     * 检查异常下载行为
     * 业务含义：检测同一IP 1小时内下载超过20次的异常行为
     */
    private void checkAbnormalDownload(DownloadLog downloadLog) {
        String hourKey = REDIS_KEY_PREFIX + IP_DOWNLOAD_COUNT_KEY + ":" + 
                        downloadLog.getIpAddress() + ":" +
                        downloadLog.getDownloadTime().format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
        
        Long downloadCount = redisTemplate.opsForValue().increment(hourKey);
        redisTemplate.expire(hourKey, 2, TimeUnit.HOURS);
        
        if (downloadCount > 20) {
            log.warn("检测到异常下载行为：IP{}在1小时内下载{}次", 
                    downloadLog.getIpAddress(), downloadCount);
            // 发送告警
            sendAbnormalDownloadAlert(downloadLog.getIpAddress(), downloadCount);
        }
    }
    
    /**
     * 获取资源实时状态
     * 业务含义：返回当前资源的总储量、当日新增量、启用/禁用占比
     */
    public Map<String, Object> getResourceRealtimeStatus() {
        Map<String, Object> status = new HashMap<>();
        
        // 总储量
        Long totalCount = resourceMetadataMapper.selectCount(null);
        status.put("totalCount", totalCount);
        
        // 当日新增量
        LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        Long todayNewCount = resourceMetadataMapper.selectTodayNewCount(today);
        status.put("todayNewCount", todayNewCount);
        
        // 启用/禁用占比
        Long enabledCount = resourceMetadataMapper.selectEnabledCount();
        Long disabledCount = totalCount - enabledCount;
        
        Map<String, Object> statusRatio = new HashMap<>();
        statusRatio.put("enabledCount", enabledCount);
        statusRatio.put("disabledCount", disabledCount);
        statusRatio.put("enabledRatio", totalCount > 0 ? (double) enabledCount / totalCount : 0);
        statusRatio.put("disabledRatio", totalCount > 0 ? (double) disabledCount / totalCount : 0);
        
        status.put("statusRatio", statusRatio);
        
        return status;
    }
    
    /**
     * 获取接口调用监控数据
     * 业务含义：返回实时调用量、每分钟峰值、调用失败率
     */
    public Map<String, Object> getApiCallMonitorData() {
        Map<String, Object> monitorData = new HashMap<>();
        
        // 实时调用量（最近1分钟）
        String currentMinute = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        String currentCountKey = REDIS_KEY_PREFIX + API_CALL_COUNT_KEY + ":" + currentMinute;
        Long currentCallCount = (Long) redisTemplate.opsForValue().get(currentCountKey);
        monitorData.put("currentCallCount", currentCallCount != null ? currentCallCount : 0);
        
        // 每分钟峰值（最近1小时）
        List<Long> peakData = getRecentPeakData();
        monitorData.put("peakData", peakData);
        
        // 调用失败率
        Double failureRate = calculateFailureRate();
        monitorData.put("failureRate", failureRate);
        
        return monitorData;
    }
    
    /**
     * 获取异常行为预警
     * 业务含义：返回当前检测到的异常行为列表
     */
    public List<Map<String, Object>> getAbnormalBehaviors() {
        List<Map<String, Object>> behaviors = new ArrayList<>();
        
        // 这里简化处理，实际应该从Redis中获取异常行为记录
        // 实际实现中，异常行为应该存储在专门的告警表中
        
        return behaviors;
    }
    
    // 私有辅助方法
    private Long getHistoricalPeak(String apiUrl) {
        // 简化实现，实际应该从历史数据中计算
        return 100L;
    }
    
    private void checkFailureRateThreshold(LocalDateTime callTime) {
        String minuteKey = REDIS_KEY_PREFIX + FAILED_CALL_COUNT_KEY + ":" + 
                          callTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        String totalKey = REDIS_KEY_PREFIX + API_CALL_COUNT_KEY + ":" + 
                         callTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
        
        Long failedCount = (Long) redisTemplate.opsForValue().get(minuteKey);
        Long totalCount = (Long) redisTemplate.opsForValue().get(totalKey);
        
        if (failedCount != null && totalCount != null && totalCount > 0) {
            double failureRate = (double) failedCount / totalCount;
            if (failureRate > 0.05) {
                log.warn("接口调用失败率过高：{}%", failureRate * 100);
                sendFailureRateAlert(failureRate);
            }
        }
    }
    
    private List<Long> getRecentPeakData() {
        // 简化实现，实际应该从Redis中获取最近1小时的数据
        return Arrays.asList(100L, 120L, 80L, 150L, 90L);
    }
    
    private Double calculateFailureRate() {
        // 简化实现，实际应该从Redis中计算
        return 0.02; // 2%
    }
    
    private void sendPeakAnomalyAlert(String apiUrl, Long currentCount, Long historicalPeak) {
        log.warn("发送峰值异常告警：接口{}当前调用量{}超过历史峰值{}", apiUrl, currentCount, historicalPeak);
        // 实际实现中应该发送到告警系统
    }
    
    private void sendAbnormalDownloadAlert(String ipAddress, Long downloadCount) {
        log.warn("发送异常下载告警：IP{}在1小时内下载{}次", ipAddress, downloadCount);
        // 实际实现中应该发送到告警系统
    }
    
    private void sendFailureRateAlert(double failureRate) {
        log.warn("发送失败率告警：当前失败率{}%", failureRate * 100);
        // 实际实现中应该发送到告警系统
    }
}
